home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / jade / lisp / modes.jl < prev    next >
Lisp/Scheme  |  1995-03-09  |  10KB  |  281 lines

  1. ;;;; modes.jl -- Code for handling editing modes.
  2. ;;;  Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
  3.  
  4. ;;; This file is part of Jade.
  5.  
  6. ;;; Jade is free software; you can redistribute it and/or modify it
  7. ;;; under the terms of the GNU General Public License as published by
  8. ;;; the Free Software Foundation; either version 2, or (at your option)
  9. ;;; any later version.
  10.  
  11. ;;; Jade is distributed in the hope that it will be useful, but
  12. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ;;; GNU General Public License for more details.
  15.  
  16. ;;; You should have received a copy of the GNU General Public License
  17. ;;; along with Jade; see the file COPYING.  If not, write to
  18. ;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.  
  21. ;;; Notes:
  22.  
  23. ;;; Major Modes:
  24. ;;;
  25. ;;; Each major mode has a function which is called to install the mode,
  26. ;;; the first thing such a function should do is check if a mode is
  27. ;;; already installed and if so remove it:
  28. ;;;
  29. ;;;  (when major-mode-kill
  30. ;;;    (funcall major-mode-kill))
  31. ;;;
  32. ;;; Now the new mode is free to install itself; generally this entails
  33. ;;; setting at least the `mode-name' and `major-mode-kill' variables
  34. ;;; and installing a local keymap. For example `lisp-mode' does this:
  35. ;;;
  36. ;;;   (setq mode-name "Lisp"
  37. ;;;        major-mode 'lisp-mode
  38. ;;;        major-mode-kill 'lisp-mode-kill
  39. ;;;        mode-comment-fun 'lisp-mode-insert-comment
  40. ;;;        keymap-path (cons 'lisp-mode-keymap keymap-path))
  41. ;;;   (eval-hook 'lisp-mode-hook)
  42. ;;;
  43. ;;; The function to be called when the mode is removed should remove the
  44. ;;; effects of the above, for example:
  45. ;;;
  46. ;;;   (setq keymap-path (delq 'lisp-mode-keymap keymap-path)
  47. ;;;        major-mode nil
  48. ;;;        major-mode-kill nil
  49. ;;;        mode-comment-fun nil
  50. ;;;        mode-name nil)
  51.  
  52. ;;; Minor Modes:
  53. ;;;
  54. ;;; These are usually harder to implement than major modes since they
  55. ;;; have to coexist with all other modes which are installed.
  56. ;;;
  57. ;;; Generally each minor mode maintains a buffer-local variable saying
  58. ;;; whether or not it's installed in the buffer. The minor mode's
  59. ;;; function usually toggles the mode on or off depending on the state of
  60. ;;; this variable.
  61. ;;;
  62. ;;; There are two functions which *must* be used to install/remove a
  63. ;;; minor mode -- `add-minor-mode' and `remove-minor-mode', see there
  64. ;;; documentation for details.
  65. ;;;
  66. ;;; Each buffer has a keymap for the bindings of all the minor modes
  67. ;;; active in the buffer (called `minor-mode-keymap'). These bindings
  68. ;;; have to be added when the mode is enabled and removed when it
  69. ;;; is disabled.
  70.  
  71.  
  72. (defvar mode-alist '(
  73. ;;; ::mode-alist-start::
  74.   ("\\.(c|h)$|^c(|-mode)$" . c-mode)
  75.   ("\\.jl$|^lisp(|-mode)$" . lisp-mode)
  76.   ("\\.(text|doc|txt|article|letter)$" . text-mode)
  77.   ("^(text(|-mode)|(.*/|)draft)$" . text-mode)
  78.   ("^indented-text(|-mode)$" . indented-text-mode)
  79.   ("\\.[s]$|^asm(|-mode)$" . asm-mode)
  80.   ("\\.[S]$|^asm-cpp(|-mode)$" . asm-cpp-mode)
  81.   ("\\.texi(|nfo)|^texinfo(|-mode)$" . texinfo-mode)
  82. ;;; ::mode-alist-end::
  83.   ) "List of all major modes which can be enabled by loading a file into
  84. a buffer. List is made of `(REGEXP . MODE)' cells; the REGEXP is matched
  85. against the mode specification (i.e. the filename), if it matches the
  86. function MODE is called to install the mode.")
  87.  
  88.  
  89. ;; Variables
  90.  
  91. (defvar major-mode nil
  92.   "The function which was used to initialise the buffer's major mode.")
  93. (make-variable-buffer-local 'major-mode)
  94.  
  95. (defvar major-mode-kill nil
  96.   "The function which should be called to remove the buffer's major mode.")
  97. (make-variable-buffer-local 'major-mode-kill)
  98.  
  99. (defvar comment-column 41
  100.   "Buffer-local variable containing the canonical column number which
  101. comments should begin at. If the line extends past this column the next
  102. tab stop after the end of the line is used instead.")
  103. (make-variable-buffer-local 'comment-column)
  104.  
  105. (make-variable-buffer-local 'mode-comment-fun)
  106.  
  107. (defvar mode-indent-line nil
  108.   "A function called to indent a specified line in the current buffer.")
  109. (make-variable-buffer-local 'mode-indent-line)
  110.  
  111. (defvar mode-forward-exp nil
  112.   "Function like `lisp-forward-sexp'.")
  113. (make-variable-buffer-local 'mode-forward-exp)
  114.  
  115. (defvar mode-backward-exp nil
  116.   "Function like `lisp-backward-sexp'.")
  117. (make-variable-buffer-local 'mode-backward-exp)
  118.  
  119.  
  120. ;; Major mode handling
  121.  
  122. (defun get-mode (name)
  123.   "Scan the alist `mode-alist' for a mode whose regexp matches NAME,
  124. returning the initialisation function of that mode (a symbol) or nil."
  125.   (let*
  126.       ((list mode-alist)
  127.        (elt nil))
  128.     (while (setq elt (car list))
  129.       (when (regexp-match (car elt) name t)
  130.     (return (cdr elt)))
  131.       (setq list (cdr list)))))
  132.  
  133. (defun init-mode (buf &optional name)
  134.   "Initialise an edit-mode for buffer BUF, either calls the function named
  135. in the buffer-local variable `major-mode' or finds a mode in `mode-alist'
  136. using one of the following to match against:
  137.   1. NAME
  138.   2. The word specified on the first line of the buffer surrounded by
  139.      `-*-...-*-' (ie, -*-texinfo-*-)
  140.   3. The value of the variable `mode-name'
  141.   4. The name of the file being edited in the buffer"
  142.   (with-buffer (unless buf (current-buffer))
  143.     (unless major-mode
  144.       (setq name (or name
  145.              (regexp-expand-line "-\\*- *([^ ]+) *-\\*-" "\\1"
  146.                      (buffer-start))
  147.              mode-name
  148.              (buffer-file-name buf)))
  149.       (setq major-mode (get-mode name)))
  150.     (when (functionp major-mode)
  151.       (funcall major-mode name))))
  152.  
  153. (defun kill-mode (&optional buf)
  154.   "Destroy the mode being used to edit buffer BUF with."
  155.   (unless buf
  156.     (setq buf (current-buffer)))
  157.   (with-buffer buf
  158.     (when major-mode-kill
  159.       (funcall major-mode-kill buf))))
  160.  
  161.  
  162. ;; Minor-mode handling
  163.  
  164. (defvar minor-mode-list ()
  165.   "List of all minor-modes enabled in this buffer.")
  166. (make-variable-buffer-local 'minor-mode-list)
  167.  
  168. (defvar minor-mode-keymap nil
  169.   "Buffer-local keymap to be used by minor-modes. This is only created
  170. the first time a minor mode calls `add-minor-mode' in the buffer.")
  171. (make-variable-buffer-local 'minor-mode-keymap)
  172.  
  173. (defun add-minor-mode (mode name &optional no-keymap)
  174.   "For use by minor-modes. MODE is the mode's function symbol. This sets up the
  175. current buffer. All minor-modes should call this before doing anything drastic.
  176. NAME is the string to be displayed in the status-line to show that the mode
  177. is enabled."
  178.   (when (memq mode minor-mode-list)
  179.     (error "Minor mode already installed" mode))
  180.   (setq minor-mode-list (cons mode minor-mode-list)
  181.     minor-mode-names (cons name minor-mode-names))
  182.   (unless (or minor-mode-keymap no-keymap)
  183.     (setq minor-mode-keymap (make-keylist)
  184.       keymap-path (cons 'minor-mode-keymap keymap-path)))
  185.   t)
  186.  
  187. (defun remove-minor-mode (mode name)
  188.   "For use by minor-modes. MODE is the mode's function symbol. Removes MODE
  189. from the current buffer."
  190.   (setq minor-mode-list (delq mode minor-mode-list)
  191.     minor-mode-names (delete name minor-mode-names))
  192.   t)
  193.  
  194.  
  195. ;; Comment handling
  196.  
  197. (defun insert-comment ()
  198.   "Insert comment delimeters on the current line, place the cursor where the
  199. comment should be written. This may or not be defined by each major mode."
  200.   (interactive)
  201.   (if (and (boundp 'mode-comment-fun) mode-comment-fun)
  202.       (funcall mode-comment-fun)
  203.     (error "No defined method for inserting comments in this buffer")))
  204.  
  205. (defun find-comment-pos ()
  206.   (let
  207.       ((pos (glyph-to-char-pos (pos (1- comment-column) nil))))
  208.     (goto-line-end)
  209.     (if (>= (line-end) pos)
  210.     (insert "\t")
  211.       (indent-to (1- comment-column)))))
  212.  
  213.  
  214. ;; Indentation
  215.  
  216. (defun indent-area (start end)
  217.   "Use the `mode-indent-line' function to indent each line between START and
  218. END."
  219.   (interactive "-m\nM")
  220.   (setq start (line-start start)
  221.     end (line-start end))
  222.   (unless mode-indent-line
  223.     (error "No method for indenting lines in this buffer"))
  224.   (while (< start end)
  225.     (funcall mode-indent-line start)
  226.     (next-line 1 start)))
  227.  
  228. (defvar newline-and-indent ()
  229.   "(newline-and-indent)
  230. Insert a newline then either call this buffer's `mode-indent-line' function
  231. or insert a tab."
  232.   (interactive)
  233.   (if (null mode-indent-line)
  234.       (insert "\n\t")
  235.     (insert "\n")
  236.     (funcall mode-indent-line)))
  237.  
  238. (defun indent-line ()
  239.   "Indent the current line."
  240.   (interactive)
  241.   (if mode-indent-line
  242.       (let
  243.       ((pos (funcall mode-indent-line)))
  244.     (when (and (posp pos) (< (char-to-glyph-pos (cursor-pos)) pos))
  245.       (goto-glyph pos))
  246.     (when (> (glyph-to-char-pos pos) (line-end))
  247.       (goto-line-end)))
  248.     (error "No method for indentation in this buffer.")))
  249.  
  250.  
  251. ;; Expressions
  252.  
  253. (defun forward-exp (&optional number)
  254.   "Move forward NUMBER expressions."
  255.   (interactive "p")
  256.   (goto-char (funcall (or mode-forward-exp 'forward-word) number)))
  257.  
  258. (defun backward-exp (&optional number)
  259.   "Move backwards NUMBER expressions."
  260.   (interactive "p")
  261.   (goto-char (funcall (or mode-backward-exp 'backward-word) number)))
  262.  
  263. (defun kill-exp (&optional number)
  264.   "Kill the next NUMBER expressions."
  265.   (interactive "p")
  266.   (kill-area (cursor-pos) (funcall (or mode-forward-exp 'forward-word)
  267.                    number)))
  268.  
  269. (defun backward-kill-exp (&optional number)
  270.   "Kills from the start of this NUMBER'th previous expression to the cursor."
  271.   (interactive "p")
  272.   (kill-area (funcall (or mode-backward-exp 'backward-word) number)
  273.          (cursor-pos)))
  274.  
  275. (defun transpose-exps (count)
  276.   "Move the expression before the cursor COUNT expressions forwards."
  277.   (interactive "p")
  278.   (transpose-items (or mode-forward-exp 'forward-word)
  279.            (or mode-backward-exp 'backward-word)
  280.            count))
  281.